package com.wutuo.aggragation.expire.service;

import cn.apestar.core.base.DelFlagEnum;
import cn.apestar.core.framework.exception.BusinessException;
import cn.apestar.core.utils.DateUtils;
import cn.apestar.sms.api.SMSAPIService;
import cn.apestar.user.api.enums.UserType;
import cn.apestar.user.provider.info.domain.User;
import cn.apestar.user.provider.institution.response.InstitutionResponse;
import cn.apestar.user.provider.institution.service.InstitutionService;
import com.wutuo.aggragation.expire.component.ExpireManagementConvertor;
import com.wutuo.aggragation.expire.dao.ExpireManagementLatestMapper;
import com.wutuo.aggragation.expire.dao.ExpireManagementMapper;
import com.wutuo.aggragation.expire.domain.ExpireManagement;
import com.wutuo.aggragation.expire.domain.ExpireManagementLatest;
import com.wutuo.aggragation.expire.dto.RosterExpireInfoDto;
import com.wutuo.aggragation.expire.dto.RosterExpireManagementLatestDto;
import com.wutuo.aggragation.expire.request.ExpireManagementAddRequest;
import com.wutuo.aggragation.expire.request.ExpireManagementLatestListRequest;
import com.wutuo.aggragation.expire.request.ExpireManagementListRequest;
import com.wutuo.aggragation.expire.response.ExpireManagementLatestResponse;
import com.wutuo.aggragation.expire.response.ExpireManagementResponse;
import com.wutuo.child.api.request.ChildRequest;
import com.wutuo.child.provider.domain.Child;
import com.wutuo.child.provider.service.ChildService;
import com.wutuo.roster.provider.constant.GradeUtil;
import com.wutuo.roster.provider.dao.RosterMapper;
import com.wutuo.roster.provider.domain.Parents;
import com.wutuo.roster.provider.domain.Roster;
import com.wutuo.roster.provider.enums.GradeEnum;
import com.wutuo.roster.provider.service.ParentsService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.Date;
import java.util.List;

@Service
public class ExpireManagementService {

    private Logger logger = LoggerFactory.getLogger(ExpireManagementService.class);

    @Autowired
    private ExpireManagementMapper expireManagementMapper;

    @Autowired
    private ExpireManagementLatestMapper expireManagementLatestMapper;

    @Autowired
    private SMSAPIService smsapiService;

    @Autowired
    private ParentsService parentsService;

    @Autowired
    private InstitutionService institutionService;

    @Autowired
    private RosterMapper rosterMapper;

    @Autowired
    private ChildService childService;

    public static final String ST_NOTFOUND = "notfound";

    public static final String ST_NORMAL = "normal";

    public static final String ST_EXPIRE = "expire";

    @Transactional
    public void add(ExpireManagementAddRequest request, Long currentUserId, Long institutionId) {

        if (request.getStartDate() != null && request.getExpireDate().compareTo(request.getStartDate()) < 0) {
            throw new BusinessException(500, "expire.fail.start.date.should.less.than.expire.date");
        }
        ExpireManagement em = new ExpireManagement();
        Date now = DateUtils.now();
        em.setCreateBy(currentUserId);
        em.setCreateDate(now);
        em.setUpdateBy(currentUserId);
        em.setUpdateDate(now);
        em.setDelFlag(DelFlagEnum.DEL_FALSE.getValue());
        em.setInstitutionId(institutionId);
        em.setRosterId(request.getRosterId());
        em.setExpireDate(request.getExpireDate());
        em.setStartDate(request.getStartDate());
        em.setFee(request.getFee());
        expireManagementMapper.insert(em);

        ExpireManagementLatest expireManagementLatest = expireManagementLatestMapper.getByRosterIdAndInstitutionId(request.getRosterId(),
                institutionId);
        if (expireManagementLatest == null) {
            ExpireManagementLatest eml = new ExpireManagementLatest();
            eml.setCreateBy(currentUserId);
            eml.setCreateDate(now);
            eml.setUpdateBy(currentUserId);
            eml.setUpdateDate(now);
            eml.setDelFlag(DelFlagEnum.DEL_FALSE.getValue());
            eml.setInstitutionId(institutionId);
            eml.setRosterId(request.getRosterId());
            eml.setExpireManagementId(em.getId());
            expireManagementLatestMapper.insert(eml);
        } else {
            ExpireManagement emMaxExpireDate = expireManagementMapper.getByRosterIdAndInstitutionIdOrderByExpireDate(request.getRosterId(),
                    institutionId);
            if (emMaxExpireDate == null || emMaxExpireDate.getExpireDate().compareTo(request.getExpireDate()) < 0) {
                expireManagementLatest.setUpdateBy(currentUserId);
                expireManagementLatest.setUpdateDate(now);
                expireManagementLatest.setExpireManagementId(em.getId());
                expireManagementLatestMapper.updateExipreManagementId(expireManagementLatest);
            }
        }

    }

    public List<ExpireManagementResponse> listByRosterId(ExpireManagementListRequest request, Long institutionId) {

        List<ExpireManagement> expireManagements = expireManagementMapper.listByRosterId(request.getRosterId(), institutionId, request.getIndex(),
                request.getSize());
        List<ExpireManagementResponse> result = ExpireManagementConvertor.convert(expireManagements);
        return result;
    }

    public List<ExpireManagementLatestResponse> listLatestByInstitutionId(ExpireManagementLatestListRequest request, Long institutionId) {

        Date deadline = request.getDeadline();
        if (deadline == null) {
            deadline = DateUtils.now();
        } else {
            if (deadline.compareTo(DateUtils.parseDate(DateUtils.now())) < 0) {
                throw new BusinessException(500, "expire.fail.deadline.should.not.less.than.current.datetime");
            }
        }

        List<RosterExpireManagementLatestDto> rosterExpireManagementLatestDtos = null;
        if (StringUtils.equals(GradeEnum.OTH.getCode(), request.getGrade())) {
            Long startYear = GradeUtil.getYearByGrade(GradeEnum.P1.getCode());
            Long endYear = GradeUtil.getYearByGrade(GradeEnum.P6.getCode());
            rosterExpireManagementLatestDtos = expireManagementMapper.listLatestByInstitutionIdOth(institutionId, startYear, endYear,
                    request.getIndex(), request.getSize());
        } else {
            Long year = null;
            if (StringUtils.isNotBlank(request.getGrade())) {
                year = GradeUtil.getYearByGrade(request.getGrade());
            }
            rosterExpireManagementLatestDtos = expireManagementMapper.listLatestByInstitutionId(institutionId, year, request.getIndex(),
                    request.getSize());
        }

        List<ExpireManagementLatestResponse> expireManagementLatestResponses = ExpireManagementConvertor
                .convertToExpireManagementLatestResponse(rosterExpireManagementLatestDtos);

        for (ExpireManagementLatestResponse res : expireManagementLatestResponses) {
            if (res.getExpireDate() == null) {
                res.setStatus(ST_NOTFOUND);
            } else if (res.getExpireDate().compareTo(deadline) >= 0) {
                res.setStatus(ST_NORMAL);
            } else if (res.getExpireDate().compareTo(deadline) < 0) {
                res.setStatus(ST_EXPIRE);
            }

        }
        return expireManagementLatestResponses;
    }

    public void remindExpire(Long rosterId, Long currentUserId, Long institutionId) {

        ExpireManagementLatest eml = expireManagementLatestMapper.getByRosterIdAndInstitutionId(rosterId, institutionId);
        if (eml == null) {
            throw new BusinessException(500, "expire.fail.latest.expire.not.found");
        }
        Date now = DateUtils.now();
        if (eml.getSmsDate() != null && eml.getSmsDate().compareTo(DateUtils.parseDate(now)) == 0) {
            throw new BusinessException(500, "expire.fail.today.sms.has.send");
        }
        List<Parents> parents = parentsService.listParentsByRosterId(rosterId);
        if (parents.size() == 0) {
            throw new BusinessException(500, "expire.fail.parents.not.found");
        }
        Roster roster = rosterMapper.selectByPrimaryKey(rosterId);
        if (roster == null) {
            throw new BusinessException(500, "expire.fail.roster.not.found");
        }
        ExpireManagement expireManagement = expireManagementMapper.selectByPrimaryKey(eml.getExpireManagementId());
        InstitutionResponse institution = institutionService.getById(roster.getCmInstitutionId());
        String content = String.format("【午托帮】您在%s的孩子%s托教到期日期为%s，请留意。", institution.getInstitutionName(), roster.getName(),
                DateUtils.formatDate(expireManagement.getExpireDate()));
        for (Parents parent : parents) {
            if (StringUtils.isNotBlank(parent.getUserPhone())) {
                try {
                    smsapiService.sendSmsByYunpian(content, parent.getUserPhone());
                } catch (IOException e) {
                    logger.error("消息发送异常", e);
                }
            }
        }
        eml.setSmsDate(now);
        eml.setUpdateBy(currentUserId);
        eml.setUpdateDate(now);
        expireManagementLatestMapper.updateSmsDate(eml);
    }

    /**
     * get roster exipre info by roster id and institution id.
     *
     * @param rosterId
     * @param institutionId
     * @return expire date(date) and whether the roster is expire(bool)
     */
    public RosterExpireInfoDto getRosterExpireInfoByRosterId(Long rosterId, User currentUser, Long institutionId) {

        ExpireManagementLatest expireManagementLatest = null;
        if (UserType.PARENT.getValue().equals(currentUser.getUserType())) {
            // parent only can see his own child info
            ChildRequest childRequest = new ChildRequest();
            childRequest.setUserId(currentUser.getId());
            childRequest.setRosterId(rosterId);
            List<Child> childList = childService.list(childRequest);
            if (childList.size() == 0) {
                throw new BusinessException("expire.fail.roster.expire.management.latest.not.found");
            }
            expireManagementLatest = expireManagementLatestMapper.getByRosterId(rosterId);
        } else {
            // other user type only can see his institution's child info
            expireManagementLatest = expireManagementLatestMapper.getByRosterIdAndInstitutionId(rosterId, institutionId);
        }
        if (expireManagementLatest == null) {
            throw new BusinessException(500, "expire.fail.roster.expire.management.latest.not.found");
        }
        ExpireManagement expireManagement = expireManagementMapper.selectByPrimaryKey(expireManagementLatest.getExpireManagementId());
        if (expireManagement == null) {
            throw new BusinessException(500, "expire.fail.roster.expire.management.latest.not.found");
        }
        boolean isExpire = false;
        if (expireManagement.getExpireDate() != null) {
            isExpire = expireManagement.getExpireDate().compareTo(DateUtils.parseDate(DateUtils.now())) < 0;
        }
        return new RosterExpireInfoDto(expireManagement.getExpireDate(), isExpire);
    }

    /**
     * delete expire management by id
     *
     * @param id            expire management id
     * @param currentUserId current user id
     * @param institutionId org id
     */
    @Transactional
    public void deleteExpireManagement(Long id, Long currentUserId, Long institutionId) {

        ExpireManagement expireManagement = expireManagementMapper.selectByPrimaryKey(id);
        if (expireManagement == null) {
            return;
        }
        Date now = DateUtils.now();
        Long rosterId = expireManagement.getRosterId();
        expireManagementMapper.deleteByPrimaryKey(id, currentUserId, now);
        ExpireManagementLatest expireManagementLatest = expireManagementLatestMapper.getByRosterIdAndInstitutionId(rosterId, institutionId);
        if (expireManagementLatest != null && id.equals(expireManagementLatest.getExpireManagementId())) {
            ExpireManagement oneOrderByExpireDateDesc = expireManagementMapper.getOneOrderByExpireDateDesc(institutionId, rosterId);
            if (oneOrderByExpireDateDesc != null) {
                expireManagementLatest.setExpireManagementId(oneOrderByExpireDateDesc.getId());
                expireManagementLatest.setUpdateDate(now);
                expireManagementLatest.setUpdateBy(currentUserId);
                expireManagementLatestMapper.updateExipreManagementId(expireManagementLatest);
            }
        }
    }

}
